package com.feige.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.feige.constant.Constants;
import com.feige.pojo.SecurityUser;
import com.feige.pojo.User;
import com.feige.pojo.dto.LoginFormDto;
import com.feige.pojo.dto.RegisterFormDto;
import com.feige.result.AjaxResult;
import com.feige.result.R;
import com.feige.service.IndexService;
import com.feige.openfeigh.UserService;
import com.feige.utils.exception.CustomException;
import com.feige.utils.exception.user.UserDisableException;
import com.feige.utils.exception.user.UserPasswordNotMatchException;
import com.feige.utils.jwt.JwtInfo;
import com.feige.utils.jwt.JwtUtils;
import com.feige.utils.redis.RedisUtils;
import com.feige.utils.validate.ValidateEmail;
import com.feige.utils.verifycode.GenerateVerifyCodeImg;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;


/**
 * @author feige
 */
@Service
public class IndexServiceImpl  implements IndexService {


    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private RedisUtils redisUtils;

    @Resource
    private JwtUtils jwtUtils;


    @Resource
    private UserService userService;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;


    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Resource
    private ValidateEmail validateEmail;


    @Override
    public AjaxResult logout(String token) {
        String userId = jwtUtils.getUserIdByToken(token);
        String key = Constants.LOGIN_USER_KEY + userId;
        redisUtils.del(key);
        return AjaxResult.success();
    }

    @Override
    public SecurityUser login(LoginFormDto loginFormDto) {
        if (loginFormDto.getFlag()) {
            String verifyKey = Constants.CAPTCHA_CODE_KEY + loginFormDto.getUuid();
            validateEmail.getVerifyCode(verifyKey, loginFormDto.getCode());
        }
        return validateUser(loginFormDto.getEmail(),loginFormDto.getPassword());
    }

    @Override
    public SecurityUser register(RegisterFormDto registerFormDto){
        User user = new User();
        String password = bCryptPasswordEncoder.encode(registerFormDto.getPassword());
        BeanUtils.copyProperties(registerFormDto,user);
        user.setPassword(password);
        R<User> r = userService.save(user);
        if (r.getCode() == 200){
            return validateUser(user.getEmail(),registerFormDto.getPassword());
        }
        return null;
    }

    @Override
    public SecurityUser getInfo(HttpServletRequest request) {
        JwtInfo jwtInfo = jwtUtils.getJwtInfoByToken(request);
        if (ObjectUtil.isNotNull(jwtInfo) && StrUtil.isNotBlank(jwtInfo.getId())){
            String key = Constants.LOGIN_USER_KEY + jwtInfo.getId();
            return (SecurityUser) redisUtils.get(key);
        }
        return null;
    }

    @Override
    public boolean senderEmailCode(String email) {
        String code = GenerateVerifyCodeImg.generateVerifyCode(6, "0123456789");
        //发送邮箱验证码
        HashMap<String, String> map = new HashMap<>(5);
        map.put("email",email);
        map.put("text","小飞云课邮箱验证码：" + code);
        rabbitTemplate.convertAndSend("EmailDirectExchange","EmailDirectRouting", map);

        //存入缓存
        String key = Constants.EMAIL_CODE_KEY + email;
        return redisUtils.set(key, code, Constants.CAPTCHA_CODE_EXPIRE);
    }

    @Override
    public void validateEmail(String email, String code) {
        validateEmail.validateEmail(email,code);
    }

    /**
     * 验证用户
     * @param username
     * @param password
     * @return
     */
    public SecurityUser validateUser(String username,String password){
        // 用户验证
        Authentication authentication;
        try {
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException){
                throw new UserPasswordNotMatchException();
            } else{
                throw new CustomException(e.getMessage());
            }
        }
        SecurityUser securityUser = (SecurityUser) authentication.getPrincipal();
        //token存入Redis中
        String key = Constants.LOGIN_USER_KEY + securityUser.getId();
        redisUtils.set(key,securityUser);
        //查看用户是被禁用
        if (securityUser.getStatus() == 0){
            throw new UserDisableException();
        }
        JwtInfo jwtInfo = new JwtInfo();
        BeanUtils.copyProperties(securityUser,jwtInfo);
        String jwtToken = jwtUtils.createTokenByJwtInfo(jwtInfo);
        securityUser.setToken(jwtToken);
        return securityUser;
    }
}
